//
// Created by 付盛原 on 24-11-8.
//

#include "QueueItem.h"

#include <future>
#include <utility>
#include <glog/logging.h>
#include <glog/log_severity.h>

namespace gui::widgets
{
    QueueItem::QueueItem(const int id, const QString& name, process_ptr ptr, QWidget* parent)
        : QWidget(parent), id(new QLabel(QString::number(id), this)),
          title(new QLabel(name, this)), statusInfo(new QLabel(this)),
          progress(new QProgressBar(this)),
          button(new QPushButton("开始")),
          box(new QHBoxLayout(this)),
          process(std::move(ptr))
    {
        // 将组件添加到布局中
        this->box->addWidget(this->id);
        this->box->addWidget(this->title);
        this->box->addWidget(this->progress);
        this->box->addWidget(this->statusInfo);
        this->box->addWidget(this->button);

        this->progress->setTextVisible(true);

        //设置组件大小
        // this->id->setFixedWidth(30);
        // this->title->setFixedWidth(50);
        this->progress->setMaximumWidth(400);
        // this->statusInfo->setFixedWidth(50);
        // this->button->setFixedWidth(40);

        // 设置信号
        connect(this->button, &QPushButton::clicked, this,
                [this]()
                {
                    if (this->is_done || this->throw_error)
                    {
                        return;
                    }
                    if (this->is_running)
                    {
                        this->button->setText("开始");
                        this->pauseProcess();
                    }
                    else
                    {
                        this->button->setText("暂停");
                        this->startProcess();
                    }
                });
        connect(this, &QueueItem::triggerDone, this, &QueueItem::processDone);

        connect(this, &QueueItem::triggerUpdateProgress, this->progress, &QProgressBar::setValue);
    }

    void QueueItem::startProcess()
    {
        if (this->is_done || this->throw_error || this->is_running)
        {
            // 如果已经完成、抛出异常或是正在运行则退出
            return;
        }
        // 异步运行转码
        this->future = std::async(
            std::launch::async,
            [this]()
            {
                this->runTranscode(false);
            });
        this->is_running.store(true);
    }

    void QueueItem::continueProcess()
    {
        if (this->is_done || this->throw_error || this->is_running)
        {
            return;
        }
        this->future = std::async(
            std::launch::async,
            [this]()
            {
                this->runTranscode(true);
            });
        this->is_running.store(true);
    }

    void QueueItem::pauseProcess()
    {
        if (this->is_done || this->throw_error || !this->is_running)
        {
            // 如果已经完成、抛出异常或是没有运行则退出
            return;
        }
        //暂停
        this->is_running.store(false);
    }

    void QueueItem::processDone()
    {
        this->statusInfo->setText("完成");
        this->button->setDisabled(true);
    }

    void QueueItem::runTranscode(bool isContinue)
    {
        using namespace std;
        if (isContinue)
        {
            this->process->continue_process();
        }
        else
        {
            this->process->start_process();
        }
        while (this->is_running && !this->is_done && !this->throw_error)
        {
            if (this->process->get_status() == utils::process::status::DONE)
            {
                LOG(INFO) << "transcode process done";
                this->is_done.store(true);
                break;
            }
            if (this->process->get_status() == utils::process::status::ERROR)
            {
                LOG(INFO) << "transcode error";
                LOG(INFO) << this->process->get_error();
                this->errorOccurred(this->process->get_error());
                this->throw_error.store(true);
                return;
            }
            if (this->process->get_status() == utils::process::status::PAUSE)
            {
                LOG(INFO) << "transcode paused";
                this->is_running.store(false);
                return;
            }
            const double present = static_cast<double>(this->process->get_current_frame()) /
                                   this->process->get_total_frames();
            LOG(INFO) << "present: " << present;
            this->triggerUpdateProgress(present);
            this_thread::sleep_for(chrono::milliseconds(300));
        }
        this->triggerDone();
        this->triggerUpdateProgress(100);
    }
}
